/*                                  ATELIER                                   */

/* %%LICENSE_TAG%%                                                            */
package edu.gmu.view.cube;

import edu.gmu.atelier.AffineVector;
import edu.gmu.atelier.Matrix;
import edu.gmu.atelier.RealVector;
import edu.gmu.atelier.Vector;
import edu.gmu.atelier.VectorFactory;
import java.awt.Graphics2D;
import javax.swing.JComponent;

import edu.gmu.view.canvas.AbstractLayer;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;

/*******************************************************************
 * Draws a cube in various rotations/positions.
 * @author  James H. Pope
 * @version $Id:$
 *******************************************************************/
public class IsometryLayer extends AbstractLayer
{
    private ControlModel controlModel = null;
    
    private double cubeScale = 100.0; // a.k.a. size of the cube
    
    
    /**
     * Creates a new CubeLayer with specified parameters.
     * @param controlModel
     */
    public IsometryLayer ( ControlModel controlModel )
    {
        this.controlModel = controlModel;
    }
    
    
    /*********************************************************************
     * Paints images on specified Component object using passed Graphics.
     *
     * @param component 
     * @param graphics
     *********************************************************************/
    public void paintLayer( JComponent  component, Graphics2D  graphics )
    {
        AffineTransform originalTransform = graphics.getTransform();

        int width  = component.getWidth();
        int height = component.getHeight();
        
        /*
         * Orient from default Java2D (upper/left) to math (lower/left)
         */
        graphics.translate( 0 , component.getHeight() ); // translate
        graphics.scale(1, -1); // flip


        Pen pen = new Pen( graphics, component );
        double aspect = width/height;
        //pen.setPerspective(Math.PI/8, aspect, 900.0, 1800.0);
        
        /*
         * Perspective has to do with the camera and the "view" box/volume.
         * The near plane and far plane are actually in the -z direction.
         * Example:
         * znear=1 zfar=10 translate object to z=+5 it will not be displayed!
         * znear=1 zfar=10 translate object to z=-5 it will be displayed.
         * This is because -5 is between -1 and -10 and +5 is not.
         */
        double znear = 1;
        double zfar  = 1000;
        
        pen.setPerspective(Math.PI/4, aspect, znear, zfar);
        Transform transform = pen.getModelView();

        transform.push();
        
        
        
        //--------------------------------------------------------------------//
        // Apply user provides translate.rotate, and scale transforms
        //--------------------------------------------------------------------//
        double xRotation = this.controlModel.getXRotation();
        double yRotation = this.controlModel.getYRotation();
        double zRotation = this.controlModel.getZRotation();
        
        double xScaling = this.controlModel.getXScaling();
        double yScaling = this.controlModel.getYScaling();
        double zScaling = this.controlModel.getZScaling();
        
        double xTranslate = this.controlModel.getXTranslate();
        double yTranslate = this.controlModel.getYTranslate();
        double zTranslate = this.controlModel.getZTranslate();
        
        // Had to apply user translate first and the the cude translate+scale 
        transform.translate(xTranslate, yTranslate, zTranslate);
        
        transform.translate(0.0, 0.0,-500);
        transform.scale(cubeScale, cubeScale, cubeScale);
        
        //transform.translate(xTranslate, yTranslate, zTranslate);
        transform.rotateX( xRotation );
        transform.rotateY( yRotation );
        transform.rotateZ( zRotation );
        transform.scale( xScaling, yScaling, zScaling );
        //--------------------------------------------------------------------//
        
        
        
        
        
        
        
//        //transform.rotateX( Math.PI/6 );
//        //transform.rotateY( Math.PI/6 );
//
//        Cube cube = new Cube(1.0);
//        pen.setColor( Color.WHITE );
//        cube.draw(component, graphics, pen);
//        
//        VectorFactory factory = a.getFactory();

//        // Unit circle
//        double radianInterval = Math.PI/64;
//        double vectorDirection= 0.0;
//        List<Vector> unitVectors = new ArrayList<Vector>();
//        while( vectorDirection < 2.0*Math.PI )
//        {
//            double x = Math.cos(vectorDirection);
//            double y = Math.sin(vectorDirection);
//            double z = 0.0;
//            Vector v = a.getFactory().makeVector( new double[]{x,y,z} );
//            unitVectors.add(v);
//            vectorDirection+=radianInterval;
//        }
        
        
////        // Unit schere
////        double radianInterval = Math.PI/16;
////        List<Vector> unitVectors = new ArrayList<Vector>();
////        // Create one "slice" of the pie in an xy plane
////        double xyVectorDirection= 0.0;
////        while( xyVectorDirection < 2.0*Math.PI )
////        {
////            double pcos = Math.cos(xyVectorDirection);
////            double nsin =-Math.sin(xyVectorDirection);
////            double psin = Math.sin(xyVectorDirection);
////            
////            // Create the "affine" rotation with translation along z-axis
////            List<Vector> v = new ArrayList<Vector>();
////            v.add( new RealVector(pcos,nsin, 0.0) );
////            v.add( new RealVector(psin,pcos, 0.0) );
////            v.add( new RealVector( 0.0, 0.0, 1.0) );
////            
////            double x = Math.cos(xyVectorDirection);
////            double y = Math.sin(xyVectorDirection);
////            double z = Math.tan( zVectorDirection);
////            Vector v = a.getFactory().makeVector( new double[]{x,y,z} );
////            unitVectors.add(v.normalize());
////            xyVectorDirection+=radianInterval;
////        }
//        
//        Matrix u = new Matrix(unitVectors, factory);
//        
//        Matrix i1 = a.mult(u);
//        Matrix i2 = a.mult(i1);
//        Matrix i3 = a.mult(i2);
//        Matrix i4 = a.mult(i3);
//        Matrix i5 = a.mult(i4);
//        
//        // Draw with circle showing over others
//        pen.setColor( Color.RED );
//        drawMatrix(u,pen);
//        pen.setColor( Color.ORANGE );
//        drawMatrix(i1,pen);
//        pen.setColor( Color.GREEN );
//        drawMatrix(i2,pen);
//        pen.setColor( Color.GREEN );
//        //drawMatrix(i3,pen);
//        pen.setColor( Color.YELLOW );
//        //drawMatrix(i4,pen);
//        pen.setColor( Color.BLUE );
//        drawMatrix(i5,pen);
        
        
        transform.pop();


        graphics.setTransform(originalTransform);
    }
    
    /**
     * Draw the vectors in the matrix - note that the graphics library
     * only knows how to deal with AffineVectors, therefore, whatever
     * type the vector was has to be converted into an AffineVector/ 
     * @param a
     * @param pen
     * @param colors 
     */
    public static final void drawMatrix( Matrix a, Pen pen, Color[] colors )
    {
        //Color[] colors = new Color[]{   Color.RED,  Color.GREEN,
        //                                Color.BLUE, Color.WHITE};
        List<Vector> vectors = a.getVectors();
        for (int i = 0; i < vectors.size(); i++)
        {
            pen.setColor( colors[i] );
            Vector v  = vectors.get(i);
            Vector vn = v.normalize();
            
            AffineVector u = new AffineVector(0.0,0.0,0.0);
            u.setElement(0, vn.getElement(0));
            u.setElement(1, vn.getElement(1));
            if( v.getLength() >= 3 )
            {
                u.setElement(2, vn.getElement(2));
            }
            
            //AffineVector v = (AffineVector)vectors.get(i);
            //AffineVector u = v.normalize();
            //System.out.println("Drawing: "+u);
            pen.drawLine(u);
        }
    }
    
    /**
     * Draw the vectors in the matrix - note that the graphics library
     * only knows how to deal with AffineVectors, therefore, whatever
     * type the vector was has to be converted into an AffineVector/ 
     * @param a
     * @param pen
     */
    public static final void drawMatrix( Matrix a, Pen pen )
    {
        //Color[] colors = new Color[]{   Color.RED,  Color.GREEN,
        //                                Color.BLUE, Color.WHITE};
        List<Vector> vectors = a.getVectors();
        for (int i = 0; i < vectors.size(); i++)
        {
            Vector vn  = vectors.get(i);
            //Vector vn = v.normalize();
            
            AffineVector u = new AffineVector(0.0,0.0,0.0);
            u.setElement(0, vn.getElement(0));
            u.setElement(1, vn.getElement(1));
            if( vn.getLength() >= 3 )
            {
                u.setElement(2, vn.getElement(2));
            }
            
            //AffineVector v = (AffineVector)vectors.get(i);
            //AffineVector u = v.normalize();
            //System.out.println("Drawing: "+u);
            pen.drawLine(u);
        }
    }
     
}

/*                                  ATELIER                                   */
